﻿using System;
using System.Threading.Tasks;
using System.Windows.Input;

using Outcoder;
using Outcoder.ApplicationModel;
using Outcoder.ComponentModel;
using Outcoder.InversionOfControl;
using Outcoder.Messaging;
using Outcoder.LauncherModel.Launchers;
using Outcoder.Services;
using Outcoder.Services.Implementation;
using Outcoder.UI.Xaml;

using Xamarin.Forms;

namespace CalciumTemplateApp
{
	/// <summary>
	/// This is the base class for viewmodels within the project.
	/// When using the Visual Studio Add New Item dialog to create
	/// a new Calcium View, the viewmodel will inherit from this class.
	/// It is, therefore, a key extensibility point for Calcium.
	/// </summary>
    public abstract class ViewModel : ViewModelBase, 
		IMessageSubscriber<SettingChangeEventArgs>, 
		IMessageSubscriber<ApplicationLifeCycleMessage>
	{
		protected ViewModel() : this((string)null)
		{
			/* Intentionally left blank. */
		}

		/// <summary>
		/// Use this constructor to supply a title for the viewmodel.
		/// The title can be later changed using the Title property.
		/// </summary>
		/// <param name="title">The title.</param>
		protected ViewModel(string title) : this(() => title)
		{
			/* Intentionally left blank. */
		}

		protected ViewModel(Func<object> titleFunc)
			: base(titleFunc)
		{
			/* Prevent an exception being raised at design time. 
			 * This allows you to use a design time data context for your view 
			 * by inserting the following attribute in a top level control: 
			 * d:DataContext="{d:DesignInstance local:YourViewModel, IsDesignTimeCreatable=True}" */
			if (EnvironmentValues.DesignTime)
			{
				return;
			}

			reviewCommand = new DelegateCommand(obj => Review());
			buyFullVersionCommand = new DelegateCommand(obj => BuyFullVersion());

			/* Messenger is a weak referencing event notification system. */
			var messageBus = Dependency.Resolve<IMessenger>();
			messageBus.Subscribe(this);
		}

		void Review()
		{
			var marketplaceService = Dependency.Resolve<IMarketplaceService>();
			marketplaceService.Review();
		}

		readonly DelegateCommand reviewCommand;

		/// <summary>
		/// Gets the review command, which causes the built-in marketplace app to launch.
		/// When debugging the marketplace task is replaced with a mock task. 
		/// See the <see cref="Bootstrapper"/> for more information.
		/// </summary>
		public ICommand ReviewCommand
		{
			get
			{
				return reviewCommand;
			}
		}

		string visualState;

		/// <summary>
		/// Gets or sets the current visual state of the app 
		/// that is automatically transitioned to using an attached property 
		/// in the view. <see cref="VisualStateUtility"/>
		/// The <c>VisualStateUtility</c> uses the VisualStateManager 
		/// to set the visual state value.
		/// </summary>
		/// <value>
		/// The view's visual state.
		/// </value>
		public string VisualState
		{
			get
			{
				return visualState;
			}
			protected set
			{
				Assign(ref visualState, value);
			}
		}

		/// <summary>
		/// Gets the global app settings.
		/// </summary>
		public AppSettings AppSettings
		{
			get
			{
				return AppSettings.Instance;
			}
		}

		/// <summary>
		/// This method is called when a setting is changed.
		/// </summary>
		/// <param name="message">
		/// The <see cref="Outcoder.Services.SettingChangeEventArgs"/> 
		/// instance containing the event data.</param>
		public virtual async Task ReceiveMessage(SettingChangeEventArgs message)
		{
			/* Setting changed. */
		}

		/// <summary>
		/// If the user has not already consented to the app running under the lock screen
		/// a confirmation dialog is displayed.
		/// </summary>
		protected async Task PromptForLockScreenConsentIfNecessary()
		{
			var lockScreenService = Dependency.Resolve<ILockScreenService, LockScreenService>();

			if (lockScreenService.UserPrompted)
			{
				return;
			}

			/* TODO: Make localizable resource. */
			bool response = await DialogService.AskYesNoQuestionAsync(
				"Allow app to run under the lock screen?"/*AppResources.Question_AllowTheAppToRunUnderTheLockScreen_Message*/,
				"Lock Screen"/*AppResources.Question_AllowTheAppToRunUnderTheLockScreen_Caption*/);

			lockScreenService.RunningUnderLockScreenEnabled = response;
			lockScreenService.UserPrompted = true;
		}

		async Task IMessageSubscriber<ApplicationLifeCycleMessage>.ReceiveMessage(ApplicationLifeCycleMessage message)
		{
			if (message.State == ApplicationLifeCycleState.Activated)
			{

			}
		}

		readonly DelegateCommand buyFullVersionCommand;

		public ICommand BuyFullVersionCommand
		{
			get
			{
				return buyFullVersionCommand;
			}
		}

		void BuyFullVersion()
		{
			var task = Dependency.Resolve<IMarketplaceDetailTask>();
			task.Show();
		}

		public INavigation Navigation { get; set; }

		[InjectDependencies]
		public AppResources AppResources { get; set; }
	}
}
